/**
  ******************************************************************************
  * @file    PrimeMotor_Driver.c
  * @author  tuancheng_Zero
  * @version V0.1
  * @date    08/05/2024
  * @brief   PrimeMotor Driver
  ******************************************************************************
*/ 
#include <includes.h>

// 局部宏定义
#define PMotor_DeviceAddr           0x0001      // 设备地址
#define PMotor_RgAddr_AcceleTime    0x000a      // 加速时间地址
#define PMotor_RgAddr_DeceleTime    0x000b      // 减速时间地址
#define PMotor_RgAddr_Start         0x2000      // 启动地址
#define PMotor_RgAddr_SetFreq       0x2001      // 频率地址
#define PMotor_RgAddr_GetStatus     0x2100      // 状态地址

// 局部变量
static PMotorOperate_ST pMotorOperate_st = {0};  // 原动机操作结构体
static uint8_t pMotor_DataTxBuff[50] = {0};      // 原动机数据缓冲
static uint8_t * PMotor_DataRxPoint = NULL;       
static uint8_t waitBusTimeout = 0;               // 等待总线超时
static uint8_t PMotorOpBit = 0;                  // 原动机操作Bit

// 全局变量
PMotorStatus_ST pMotorStatus_st = {0};           // 原动机状态结构体

/// @brief 数据处理函数
/// @param pData 数据缓冲
/// @param length 数据长度
/// @return 
uint8_t PMotor_RecvHandle(uint8_t * pData){
    // 释放RS485总线
    OSSemPost((OS_EVENT *)App_Sem_RS485BUSIDLE);
    waitBusTimeout = 0;
    // 通知数据接收完成
    PMotor_DataRxPoint = pData;
    OSSemPost((OS_EVENT *)App_Sem_PMOTORRC);
    
    return DEF_TRUE;
}

/// @brief 数据传输
/// @param cmd 命令号
/// @param addr 寄存器地址
/// @param data 单个数据内容(cmd为03H时输入长度 cmd为06H时输入内容)
/// @return 0失败  1成功
static uint8_t PMotor_TransferData(uint8_t cmd, uint16_t addr, uint16_t data){
    uint8_t os_err;
    uint16_t crcValue = 0;

    // 等待RS485总线空闲
    OSSemPend((OS_EVENT *)App_Sem_RS485BUSIDLE, OS_TICKS_PER_SEC * 1, &os_err);// 1秒后超时
    if(os_err == OS_ERR_TIMEOUT)
        waitBusTimeout = 1;
    // 数据组织
    pMotor_DataTxBuff[0] = PMotor_DeviceAddr;
    pMotor_DataTxBuff[1] = cmd;
    pMotor_DataTxBuff[2] = addr >> 8;
    pMotor_DataTxBuff[3] = addr;
    pMotor_DataTxBuff[4] = data >> 8;
    pMotor_DataTxBuff[5] = data;
    // 计算校验和
    crcValue = Comm_CalCRC16(pMotor_DataTxBuff, 6);
    pMotor_DataTxBuff[6] = crcValue >> 8;
    pMotor_DataTxBuff[7] = crcValue;
    // 往RS485发送数据
    RS485_DmaTransferData(pMotor_DataTxBuff, 8);

    return DEF_TRUE;
}

/// @brief 写单个寄存器数据0x06
/// @param addr 寄存器地址
/// @param data 数据
/// @return 0失败  1成功
static uint8_t PMotor_WriteSingleRegister(uint16_t addr, uint16_t data){
    uint8_t os_err = 0;

    // 发送数据
    if(PMotor_TransferData(0x06, addr, data) != DEF_TRUE)
        return DEF_FALSE;
    // 等待接收变频器响应(等1秒)
    OSSemPend((OS_EVENT *)App_Sem_PMOTORRC,OS_TICKS_PER_SEC / 2,&os_err);
    if(os_err == OS_ERR_TIMEOUT)
        return DEF_FALSE;
    // 判断接收内容是否与发送内容一致
    if(memcmp(pMotor_DataTxBuff, PMotor_DataRxPoint, 8) == 0)
        return DEF_TRUE;
    return DEF_FALSE;
}

/// @brief 获取变频器状态
/// @param  none
/// @return 0失败  1成功
uint8_t PMotor_QueryStatus(void){
    uint8_t os_err = 0;

    // 发送数据
    if(PMotor_TransferData(0x03, PMotor_RgAddr_GetStatus, 0x04) != 1)
        return DEF_FALSE;
    // 等待接收变频器响应(等0.5秒)
    OSSemPend((OS_EVENT *)App_Sem_PMOTORRC,OS_TICKS_PER_SEC / 2,&os_err);
    if(os_err == OS_ERR_TIMEOUT)
        return DEF_FALSE;
    // 匹配命令号
    if(PMotor_DataRxPoint[1] != 0x03)
        return DEF_FALSE;
    // 获取状态数据
    pMotorStatus_st.ruing = PMotor_DataRxPoint[6] & 0x01;
    pMotorStatus_st.stop = (PMotor_DataRxPoint[6] >> 1) & 0x01;
    pMotorStatus_st.fwd = (PMotor_DataRxPoint[6] >> 3) & 0x01;
    pMotorStatus_st.rev = (PMotor_DataRxPoint[6] >> 4) & 0x01;
    pMotorStatus_st.errorCode = (PMotor_DataRxPoint[3] << 8) | PMotor_DataRxPoint[4];
    pMotorStatus_st.setFreq = ((PMotor_DataRxPoint[7] << 8) | PMotor_DataRxPoint[8]) / 100;
    pMotorStatus_st.curFreq = ((PMotor_DataRxPoint[9] << 8) | PMotor_DataRxPoint[10]) / 100;
    return DEF_TRUE;
}

/// @brief 启动停止原动机
/// @param  mode 运行模式(1：启动 0：停止)
/// @return 0失败  1成功
static uint8_t PMotor_StartStop(uint8_t mode){
    uint16_t startMode = 0;
    //模式判断
    if(mode == 1)
        startMode = 0x12;
    else
        startMode = 0x11;
    // 发送数据
    if(PMotor_WriteSingleRegister(PMotor_RgAddr_Start, startMode) == 0)
        return DEF_FALSE;
    
    // 查询变频器状态
    if(PMotor_QueryStatus() != 1)
        return DEF_FALSE;
    if(pMotorStatus_st.ruing == 1)
        return DEF_TRUE;
    return DEF_FALSE;
}

/// @brief 设定原动机运行频率
/// @param Frequence 频率数值（倍率0.01）
/// @return 0失败  1成功
static uint8_t PMotor_SetFrequence(uint16_t Frequence){
    // 发送数据
    return PMotor_WriteSingleRegister(PMotor_RgAddr_SetFreq, Frequence);
}

/// @brief 设定原动机加减速时间
/// @param mode 0加速时间   1减速时间
/// @param time 时间（倍率0.1）
/// @return 0失败  1成功
static uint8_t PMotor_SetAccDecTime(uint8_t mode, uint16_t time){
    if(mode == 0)
        return PMotor_WriteSingleRegister(PMotor_RgAddr_AcceleTime, time);
    return PMotor_WriteSingleRegister(PMotor_RgAddr_DeceleTime, time);
}

/// @brief 设置操作Bit
/// @param opBit bit标志
static void PMotor_SetOperateBit(uint8_t opBit){
    uint8_t os_err;

    OSSemPend((OS_EVENT *)App_Sem_OPERATE, 0, &os_err);
    PMotorOpBit |= opBit;
    OSSemPost((OS_EVENT *)App_Sem_OPERATE);
}

/// @brief 获取操作Bit
/// @param opBit Bit标志
/// @return 0失败  1成功
static uint8_t PMotor_GetOperateBit(uint8_t opBit){
    uint8_t ret = 0;
    uint8_t os_err;
    
    OSSemPend((OS_EVENT *)App_Sem_OPERATE, 0, &os_err);
    if(PMotorOpBit & opBit)
        ret = DEF_TRUE;
    else
        ret = DEF_FALSE;
    OSSemPost((OS_EVENT *)App_Sem_OPERATE);
    return ret;
}

/// @brief 清除操作标志位
/// @param opBit Bit标志
/// @return 0失败  1成功
static void PMotor_ClearOperateBit(uint8_t opBit){
    uint8_t os_err;
    
    OSSemPend((OS_EVENT *)App_Sem_OPERATE, 0, &os_err);
    PMotorOpBit &= ~opBit;
    OSSemPost((OS_EVENT *)App_Sem_OPERATE);
}

/// @brief 原动机工作模式切换
/// @param mode 1启动   0停止
/// @param freq 频率值（倍率0.01）
/// @param time 时间值（倍率0.1）
/// @return 0失败  1成功
uint8_t PMotor_WorkModeSwitch(PRIRUNTYPE mode, uint16_t freq, uint16_t time){
    PMotor_SetOperateBit(PMotor_WorkModeSwBit);
    pMotorOperate_st.setFreq = freq;
    pMotorOperate_st.setMode = mode;
    pMotorOperate_st.setTime = time;
    // 发布事件对原动机进行操作
    SetOSFlagsForNewInform(App_Flags_RS485Handle, RS485HandleFlags_PMotorOperate);
    return DEF_TRUE;
}

/// @brief 设定原动机运行频率
/// @param freq 频率数值（倍率0.01）
/// @return 0失败  1成功
uint8_t PMotor_SetFrequenceEx(uint16_t freq){
    PMotor_SetOperateBit(PMotor_SetFreqBit);
    pMotorOperate_st.setFreq = freq;
    // 发布事件对原动机进行操作
    SetOSFlagsForNewInform(App_Flags_RS485Handle, RS485HandleFlags_PMotorOperate);
    return DEF_TRUE;
}

/// @brief 原动机操作函数
/// @param  none
/// @return 0失败  1成功
uint8_t PMotor_FuncOperate(void){
    // 变频器启动
    if(PMotor_GetOperateBit(PMotor_WorkModeSwBit) == DEF_TRUE){
        if(pMotorOperate_st.setMode == 1){
            if(pMotorStatus_st.ruing == 1)
                return PMotor_STATU_RUNING;
            if(PMotor_SetAccDecTime(0, pMotorOperate_st.setTime) == 0)
                return DEF_FALSE;
            if(PMotor_SetFrequence(pMotorOperate_st.setFreq) == 0)
                return DEF_FALSE;
            if(PMotor_StartStop(pMotorOperate_st.setMode) == 0)
                return DEF_FALSE;
        }
        else{
            if(pMotorStatus_st.stop == 1)
                return PMotor_STATU_STOP;
            if(PMotor_SetAccDecTime(1, pMotorOperate_st.setTime) == 0)
                return DEF_FALSE;
            if(PMotor_StartStop(pMotorOperate_st.setMode) == 0)
                return DEF_FALSE;
        }
        PMotor_ClearOperateBit(PMotor_WorkModeSwBit);
    }
    // 频率修改
    if(PMotor_GetOperateBit(PMotor_SetFreqBit) == DEF_TRUE){
        if(PMotor_SetFrequence(pMotorOperate_st.setFreq) == DEF_FALSE)
            return DEF_FALSE;
        PMotor_ClearOperateBit(PMotor_SetFreqBit);
    }
    return DEF_TRUE;
}
